﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using AZROLESLib;
using AzManContrib.MVC.Html.Behaviors;
using System.Web.Mvc.Html;

namespace AzManContrib.MVC.Html
{
    public static class DropDownListExtensions
    {

        /* 
         * Non generic with operation by name
         */
        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string operation)
        {
            return DropDownListFor(htmlHelper, expression, selectList, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, object htmlAttributes, string operation)
        {
            return DropDownListFor(htmlHelper, expression, selectList, htmlAttributes, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, IDictionary<string, object> htmlAttributes, string operation)
        {
            return DropDownListFor(htmlHelper, expression, selectList, htmlAttributes, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel, string operation)
        {
            return DropDownListFor(htmlHelper, expression, selectList, optionLabel, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel, object htmlAttributes, string operation)
        {
            return DropDownListFor(htmlHelper, expression, selectList, optionLabel, htmlAttributes, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes, string operation)
        {
            return DropDownListFor(htmlHelper, expression, selectList, optionLabel, htmlAttributes, AzMan.Application.Operations.FindByName(operation));
        }

        /* 
         * Non generic method, thus using AzMan.Defaults.UI.DenyiedBehavior 
         */
        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, IAzOperation operation)
        {
            Func<HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, IEnumerable<SelectListItem>, IAzOperation, MvcHtmlString> genMethod = DropDownListFor<TModel, TProperty, HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { typeof(TModel), typeof(TProperty), AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, expression, selectList, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, object htmlAttributes, IAzOperation operation)
        {
            Func<HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, IEnumerable<SelectListItem>, object,  IAzOperation, MvcHtmlString> genMethod = DropDownListFor<TModel, TProperty, HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { typeof(TModel), typeof(TProperty), AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, expression, selectList, htmlAttributes, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, IDictionary<string, object> htmlAttributes, IAzOperation operation)
        {
            Func<HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, IEnumerable<SelectListItem>, IDictionary<string, object>, IAzOperation, MvcHtmlString> genMethod = DropDownListFor<TModel, TProperty, HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { typeof(TModel), typeof(TProperty), AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, expression, selectList, htmlAttributes, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel, IAzOperation operation)
        {
            Func<HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, IEnumerable<SelectListItem>, string, IAzOperation, MvcHtmlString> genMethod = DropDownListFor<TModel, TProperty, HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { typeof(TModel), typeof(TProperty), AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, expression, selectList, optionLabel, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel, object htmlAttributes, IAzOperation operation)
        {
            Func<HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, IEnumerable<SelectListItem>, string, object, IAzOperation, MvcHtmlString> genMethod = DropDownListFor<TModel, TProperty, HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { typeof(TModel), typeof(TProperty), AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, expression, selectList, optionLabel, htmlAttributes, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes, IAzOperation operation)
        {
            Func<HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, IEnumerable<SelectListItem>, string, IDictionary<string, object>, IAzOperation, MvcHtmlString> genMethod = DropDownListFor<TModel, TProperty, HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { typeof(TModel), typeof(TProperty), AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, expression, selectList, optionLabel, htmlAttributes, operation }) as MvcHtmlString;
        }
        
        /* 
         * Generic methods, thus you can provide an inhibition behavior.
         */
        public static MvcHtmlString DropDownListFor<TModel, TProperty, TBehavior>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return htmlHelper.DropDownListFor<TModel, TProperty, TBehavior>(expression, selectList, null /* optionLabel */, null /* htmlAttributes */, operation);
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty, TBehavior>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, object htmlAttributes, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return htmlHelper.DropDownListFor<TModel, TProperty, TBehavior>(expression, selectList, null /* optionLabel */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes), operation);
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty, TBehavior>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, IDictionary<string, object> htmlAttributes, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return htmlHelper.DropDownListFor<TModel, TProperty, TBehavior>(expression, selectList, null /* optionLabel */, htmlAttributes, operation);
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty, TBehavior>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return htmlHelper.DropDownListFor<TModel, TProperty, TBehavior>(expression, selectList, optionLabel, null /* htmlAttributes */, operation);
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty, TBehavior>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel, object htmlAttributes, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return htmlHelper.DropDownListFor<TModel, TProperty, TBehavior>(expression, selectList, optionLabel, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes), operation);
        }

        public static MvcHtmlString DropDownListFor<TModel, TProperty, TBehavior>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            TBehavior behavior = new TBehavior();

            if (!HttpContext.Current.User.Can(operation))
            {
                if (!behavior.ShouldRender)
                    return MvcHtmlString.Empty;
                return htmlHelper.DropDownListFor(expression, selectList, optionLabel, behavior.GetHtmlAttributes(htmlAttributes));
            }
            return htmlHelper.DropDownListFor(expression, selectList, optionLabel, htmlAttributes);
        }
    }
}